<?php

/**
 * Утилита получения элементов формы на основе структуры таблицы в БД.
 *
 */
abstract class Kernel_Form_FromTable {

    /**
     * Проекция типов полей MySQL на типы полей формы.
     * :TODO: morozov 31072007: надо расширять по мере необзодимости.
     *
     * @var array
     */
    static private $_types = array(
        'int'       => 'integer',
        'tinyint'   => 'integer',
        'decimal'   => 'float',

        'char'      => 'string',
        'varchar'   => 'string',

        'longtext'      => 'text',
        'text'      => 'text',
        'tinytext'  => 'text',

        'date'      => 'date',
        'datetime'  => 'datetime',
        'timestamp' => 'datetime',

        'enum'      => 'list',
    );

    /**
     * Возвращает поля, сгенерированные из указанной таблицы, включая только
     * указанные наименования.
     *
     * @param   string  $table
     * @param   array   $names
     * @return  array
     */
    static public function inclusive($table, $names = array()) {
        return self::_generate(array_extract(self::_getFields($table), $names));
    }

    /**
     * Возвращает поля, сгенерированные из указанной таблицы, исключая
     * указанные наименования.
     *
     * @param   string  $table
     * @param   array   $names
     * @return  array
     */
    static public function exclusive($table, $names) {
        return self::_generate(array_diff_key(self::_getFields($table), array_flip($names)));
    }

    /**
     * Возвращает поля, сгенерированные из указанной таблицы.
     *
     * @param   string  $table
     * @return  array
     */
    static private function _getFields($table) {
        return database::fetchAssoc('SHOW FIELDS FROM `' . database::escape($table) . '`');
    }

    /**
     * Генерирует описания полей из параметров полей таблицы.
     *
     * @param   array   $fields
     * @return  array
     */
    static private function _generate($fields) {
        $elements = array();
        foreach ($fields as $name => $params) {
            if (!is_array($params = self::_parse($params))) {
                trigger_error('Unable to create element from `' . $name . '` field', E_USER_ERROR);
            }
            $elements[$name] = $params;
        }
        return $elements;
    }

    /**
     * Разбирает параметры поля таблицы и возвращает параметры элемента формы.
     *
     * @param   array   $params
     * @return  array
     */
    static private function _parse($params) {
        list($type, $length, $unsigned) = self::_split($params['Type']);
        if (!isset(self::$_types[$type])) {
            return null;
        }
        $result = array(
            'type' => self::$_types[$type],
            'validators' => self::_getValidators(self::$_types[$type], $params['Type'], $length),
        );
        if ('enum' == $type) {
            $values = array_map(create_function('$value', 'return trim($value, "\'");'), explode(',', $length));
            $result['values'] = array_combine($values, $values);
        }
        return $result;
    }

    static private function _split($type) {
        if (preg_match('/^([a-z]+)(\(([^\)]*)\))?\s*(\bunsigned\b)?/i', $type, $matches)) {
            return array($matches[1], isset($matches[3]) ? $matches[3] : null, isset($matches[6]));
        }
        trigger_error('Unable to parse field type "' . $type . '"', E_USER_ERROR);
        return null;
    }

    static private function _getValidators($type, $sql_type, $length) {
        $validators = array();
        switch ($type) {
            case 'string':
                $validators[] = array('string', array('max' => $length));
                break;
            case 'tinytext':
                $validators[] = array('string', array('max' => 256));
                break;
            default:
                break;
        }
        return $validators;
    }
}
